 #include <xpm/minimize.xpm>
 #include <xpm/netpad.xpm>
 #include <xpm/close.xpm>

 #include "controls.h"
 #include "common.h"
 #include "jabber.h"
 #include "ftp.h"
 #include "netpad.h"
 #include "util.h"

 connection     c_list[MAX_SESSIONS];
 wxCondition  * m_condition;
 wxMutex      * m_mutex;
 void         * m_ErrPopUp;
 
 extern wxColour g_colour;

 /* custom events for inter-thread communication */

 DEFINE_EVENT_TYPE(wxEVT_XMPP)
 DEFINE_EVENT_TYPE(wxEVT_FTP)

 BEGIN_EVENT_TABLE(NP, wxFrame)
   EVT_COMMAND(wxID_ANY, wxEVT_XMPP, NP::xmpp_state_machine)
   EVT_COMMAND(wxID_ANY, wxEVT_FTP, NP::ftp_state_machine)
 END_EVENT_TABLE()

 BEGIN_EVENT_TABLE(TBIcon, wxTaskBarIcon)
   EVT_MENU (PU_SOUT, TBIcon::OnSignOut)
   EVT_MENU (PU_OPEN, TBIcon::OnOpen)
   EVT_MENU (PU_EXIT, TBIcon::OnExit)
   EVT_TASKBAR_LEFT_DCLICK (TBIcon::OnLeftDClick)
 END_EVENT_TABLE()

 void
  NP::put_cfg(const char *section, wxString value, bool bDeleteLast)
 {
   wxString  line;
   wxString  appdata;
   bool      bFound = false;

   wxGetEnv(wxString("APPDATA"), &appdata);
     
   wxTextFile tfile(appdata + "/np.cfg");

   tfile.Exists() ? tfile.Open() : tfile.Create();

   for (line = tfile.GetFirstLine(); !tfile.Eof(); line = tfile.GetNextLine()) {
     if (!line.CmpNoCase(section)) {
       bFound = true;
       break;
     }
   }

   if (!bFound) {
     tfile.AddLine(section);
   }

   tfile.InsertLine(value, tfile.GetCurrentLine() + 1);

   if (bDeleteLast) {
    line = tfile.GetNextLine();
    line = tfile.GetNextLine();

    if (!tfile.Eof() && line[0] != '[') {
     tfile.RemoveLine(tfile.GetCurrentLine());
    }
   }
   
   if (tfile.IsOpened()) {
     tfile.Write();
     tfile.Close();
   }
 }

 void
  NP::get_cfg(const char *section, wxString *value)
 {
   wxString  line;
   wxString  appdata;
   bool      bFound = false;

   wxGetEnv(wxString("APPDATA"), &appdata);

   wxTextFile tfile(appdata + "/np.cfg");

   tfile.Exists() ? tfile.Open() : tfile.Create();

   for (line = tfile.GetFirstLine(); !tfile.Eof(); line = tfile.GetNextLine())
   {
     line.Trim(true);
     line.Trim(false);

     if (!line.CmpNoCase(section)) {
       bFound = true;
       break;
     }
   }

   if (bFound) {
  
     line = tfile.GetNextLine();

      if (!tfile.Eof() && line[0] != '[') {
        *value = line;
      }
   }
 }

 void 
  NP::OnLeftDClick(wxMouseEvent& WXUNUSED(e)) 
 {
   static bool border;

   border ? (SetWindowStyleFlag(wxCLIP_CHILDREN|wxNO_BORDER|wxTAB_TRAVERSAL) , border = 0)
          : (SetWindowStyleFlag(wxCLIP_CHILDREN|wxRESIZE_BORDER|wxTAB_TRAVERSAL) , border = 1);

   Refresh();
 }

 void
  NP::OnLeftDown (wxMouseEvent& e)
 {
   CaptureMouse();
   wxPoint pos = ClientToScreen(e.GetPosition());
   wxPoint origin = GetPosition();
   int dx =  pos.x - origin.x;
   int dy = pos.y - origin.y;
   m_delta = wxPoint(dx, dy);
 }

 void 
  NP::OnMotion (wxMouseEvent& e)
 {
   wxPoint pt = e.GetPosition();
   wxPoint pos;

   if (HasCapture() && e.Dragging() && e.LeftIsDown()) {
     pos = ClientToScreen(pt);
     Move(wxPoint(pos.x - m_delta.x, pos.y - m_delta.y));
   }
 }

 void
  NP::OnPaint (wxPaintEvent& e) 
 { 
   wxPaintDC dc(this);

   dc.Clear();

   if (p2 && p2->IsShown()) {

     dc.GradientFillLinear( wxSize(szTitle->GetSize()), g_colour, *wxWHITE, wxSOUTH);
   
   } else { /* login screen */

     dc.GradientFillLinear(GetClientRect(), g_colour, *wxWHITE, wxSOUTH);
   }

   e.Skip();
 }

 void
  NP::OnClose (wxCloseEvent& e)
 {
   if (!GetParent()) {
     put_cfg("[Colour]", g_colour.GetAsString());
     remove_protocol_panel(); 
   }

   this->Destroy();

   e.Skip(); 
 }

 void
  NP::remove_protocol_panel (void)
 {
   Freeze();

   if (p2) {

     szTop->Detach(p2);
     p2->Hide();
     p2->Destroy(), p2 = 0;

     Disconnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(NP::OnLeftDClick));
   }

   m_user->Enable();
   m_password->Enable();
   n_connect->Enable();
   SetSize(n_size);
   
   szTop->Show(szQC, true);
   szTop->Layout(); 
   Show();
   Thaw();
 }

 void
  NP::OnText (wxCommandEvent& e) 
 {
   if ((m_user->GetValue()).Len() &&
       (m_password->GetValue()).Len() &&
       (n_chat_g->m_check || n_chat_f->m_check)) {

     n_connect->Enable();

   } else {

     n_connect->Disable();
   }

   e.Skip();
 }

 void
  NP::session_connect (wxCommandEvent& WXUNUSED(e))
 {
   state_connecting();
 }

 void
  NP::state_connecting (void)
 {
   if (m_user->GetValue().IsEmpty()) {
     show_error(m_user, "Please enter the user name", 1);
     return;
   }

   if (m_password->GetValue().IsEmpty()) {
     show_error(m_password, "Please enter the password", 1);
     return;
   }

   if (!n_chat_g->m_check &&
       !n_chat_f->m_check) {
     show_error(n_connect, "Please select the type of chat", 1);
     return;
   }
   
   Freeze();
      
   wxString userid = m_user->GetValue();

   if (n_chat_g->m_check &&
       userid.AfterFirst('@').CmpNoCase("gmail.com")) {
     userid.Append("@gmail.com");
   }

   connection *c = new connection;

   memset(c, 0, sizeof(connection));

   c->m_user      = new wxString(userid);
   c->m_password  = new wxString(m_password->GetValue());
   c->isPrimary   = true;

   strcpy(c->m_port, "5222");

   c->m_protocol = PROTO_XMPP;
   
   if (!GetParent()) {
     
     p2 = new Jabber (this);
   
     p2->Hide();
   
     szTop->Add (p2, 1, wxEXPAND, 5);

     szTop->Layout();
    }
   
   if (n_chat_g->m_check) {
     strcat(c->m_host, "talk.google.com");
     queue_connection (c);
   }

   if (n_chat_f->m_check) {
     c->m_host[0] = '\0';
     strcat(c->m_host, "chat.facebook.com");
     c->m_user = new wxString(m_user->GetValue());
     queue_connection (c);
   }
   
   /* 
    * delete c as queue_connection would do 
    * a memcpy on this connection object
    */

   delete c;
   
   m_password->Disable();

   m_user->Disable();
  
   n_connect->Disable();
 
   if (GetParent()) {
      Close(true);
   }
   
   Thaw();
 }
 
 NP::NP(wxWindow *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style)
    : wxFrame(parent, id, title, pos, size, style)
 {
   p2 = 0;
   old_logger = 0;
   m_taskBarIcon = 0;
   
   if (!parent) {
    old_logger = wxLog::GetActiveTarget();
   }

   wxString colour;

   get_cfg("[Colour]", &colour);   

   if (colour.Len()) {
     g_colour.Set(colour);
   } else {
     g_colour.Set(0, 128, 0);
   }

   szTop = new wxBoxSizer(wxVERTICAL);     /* top level sizer */

   szTitle = new wxBoxSizer(wxHORIZONTAL); /* title bar */

   szTitle->SetMinSize(-1, 30);
   
   szQC = new wxBoxSizer(wxVERTICAL);      /* connect bar */

   n_menu = new QTab(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTRANSPARENT_WINDOW, _("Menu"), NULL, "menu", false);

   n_menu->m_textcolourhighlight = *wxCYAN;
   n_menu->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxT("Verdana")));
   n_menu->m_active = false;
   
   szTitle->Add (n_menu, 0, wxLEFT|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5);

   szTitle->Add (0, 0, 1, wxEXPAND, 5);    /* spacer */

   szMinMax = new wxBoxSizer(wxHORIZONTAL);

   n_minus = new QBitmap(this, wxID_ANY, wxBitmap(minimize_xpm), wxDefaultPosition, wxDefaultSize, 0|wxTRANSPARENT_WINDOW, "bitmap_minus");
   n_minus->SetToolTip(_("Minimize"));
   szMinMax->Add (n_minus, 0, wxALL|wxALIGN_BOTTOM, 5);

   n_close = new QBitmap(this, wxID_ANY, wxBitmap(close_xpm), wxDefaultPosition, wxDefaultSize, 0|wxTRANSPARENT_WINDOW, "bitmap_close");
   n_close->SetToolTip(_("Send to tray"));
   szMinMax->Add (n_close, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_BOTTOM, 5);
 
   szTitle->Add (szMinMax, 0, 0|wxLEFT|wxBOTTOM, 5);

   wxArrayString   hosts, users;
   wxString        value;

   wxGetEnv(wxString("APPDATA"), &value);

   wxTextFile tfile(value + "/np.cfg");

   /* wxTextFile tfile("./np.cfg"); */

   tfile.Exists() ? tfile.Open() : tfile.Create();

   wxString line;
   char stanza;

   hosts.Add("talk.google.com", 1);
   hosts.Add("chat.facebook.com", 1);
   
   for (line = tfile.GetFirstLine(); !tfile.Eof(); line = tfile.GetNextLine())
   {
     stanza = '\0';

     if (!line.CmpNoCase("[Host]")) {
       stanza = 'h';
     } else if (!line.CmpNoCase("[User]")) {
       stanza = 'u';
     }

     if (stanza != '\0') {

       line = tfile.GetNextLine();

       if (stanza == 'h') {
         hosts.Add (line, 1);
       } else if (stanza == 'u') {
         users.Add (line, 1);
       }
     }
   }

   if (tfile.IsOpened()) {
     tfile.Close();
   }

   wxBoxSizer* szUser;
   szUser = new wxBoxSizer(wxHORIZONTAL);

   QTab *m_textUser = new QTab(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTRANSPARENT_WINDOW, _("Username:"), NULL, "label", false);

   m_textUser->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxT("Verdana")));
   m_textUser->m_active = false;
   
   szUser->Add (m_textUser, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);

   szUser->Add (0, 0, 1, wxEXPAND, 5);
  
   m_user = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(180,-1), 0|wxSIMPLE_BORDER );
   m_user->SetFont(wxFont(11, 70, 90, 90, false, wxEmptyString));
   m_user->SetToolTip(_("Enter the user name"));
   m_user->AutoComplete(users);
   m_user->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(NP::OnText), NULL, this);

   szUser->Add (m_user, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 8);

   szQC->Add (szUser, 0, wxEXPAND|wxALL, 5);

   wxBoxSizer* szPassword;
   szPassword = new wxBoxSizer(wxHORIZONTAL);

   QTab *m_textPassword = new QTab(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTRANSPARENT_WINDOW, _("Password:"), NULL, "label", false);

   m_textPassword->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxT("Verdana")));
   m_textPassword->m_active = false;
   
   szPassword->Add (m_textPassword, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5);

   szPassword->Add (0, 0, 1, wxEXPAND, 5);

   m_password = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(180,-1), 0|wxSIMPLE_BORDER|wxTE_PASSWORD|wxTE_PROCESS_ENTER);
   m_password->SetFont(wxFont(11, 70, 90, 90, false, wxEmptyString));
   m_password->SetToolTip(_("Enter the password"));

   m_password->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(NP::OnText), NULL, this);
   m_password->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(NP::OnConnect), NULL, this );

   szPassword->Add (m_password, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 8);

   szQC->Add (szPassword, 0, wxEXPAND|wxALL, 5);
   
   wxBoxSizer* szChat;
   szChat = new wxBoxSizer(wxHORIZONTAL);   

   n_chat_g = new QTab(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTRANSPARENT_WINDOW, _("Google"), check_xpm, "chat_g", true);
   n_chat_g->m_highlight = new wxPen(g_colour);
   n_chat_g->m_check = true;
   n_chat_g->m_round = false;
   szChat->Add(n_chat_g, 0, wxALL, 5);
   
   n_chat_f = new QTab(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTRANSPARENT_WINDOW, _("Facebook"), checkdim_xpm, "chat_f", true);
   n_chat_f->m_check = false;   
   n_chat_f->m_round = false;
   n_chat_f->m_highlight = new wxPen(g_colour);   
   szChat->Add(n_chat_f, 0, wxALL, 5);   

   szQC->Add (szChat, 0, wxALIGN_CENTER_HORIZONTAL, 5);

   szQC->Add (0, 0, 1, wxEXPAND|wxALL, 5);

   n_connect = new wxButton(this, wxID_ANY, wxT("Connect"), wxDefaultPosition, wxSize(100,-1), 0|wxNO_BORDER );
   n_connect->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(NP::OnConnect), NULL, this);
   n_connect->Disable();

   szQC->Add (n_connect, 0, wxBOTTOM|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5);

   m_password->MoveAfterInTabOrder(m_user);

   n_status = new QTab(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTRANSPARENT_WINDOW, " ", NULL, "label", false);
 
   n_status->SetFont(wxFont(wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxT("Verdana")));

   szQC->Add (n_status, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5);

   szTop->Add (szTitle, 0, wxEXPAND, 5);
   szTop->Add (szQC, 0, wxEXPAND, 5);

   szTop->Layout();

   if (!parent) {
     wxLog::SetActiveTarget(this);
   } else {
     n_menu->Hide();   
   }

   this->SetSizer(szTop);
   
   this->SetSize(ClientToWindowSize(szTop->GetMinSize()));

   this->Layout();

   this->Connect(wxEVT_IDLE, wxIdleEventHandler(NP::OnIdle));
   this->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(NP::OnEraseBackground));
   this->Connect(wxEVT_PAINT, wxPaintEventHandler(NP::OnPaint));
   this->Connect(wxEVT_SIZE, wxSizeEventHandler(NP::OnSize));
   this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(NP::OnClose));
   this->Connect(wxEVT_MOTION, wxMouseEventHandler(NP::OnMotion));
   this->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(NP::OnLeftDown));
   this->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(NP::OnLeftUp));

   m_user->SetFocus();

   if (!GetParent()) {
     m_taskBarIcon = new TBIcon();
 
     if (!m_taskBarIcon->SetIcon(wxIcon(netpad_xpm), "Login ...")) {
      assert(false);
     }
   }
 }

 NP::~NP()
 {
   if (m_taskBarIcon) {
     delete m_taskBarIcon, m_taskBarIcon = NULL;
   }

   if (old_logger) {
     wxLog::SetActiveTarget(old_logger);
   }
 }

 IMPLEMENT_APP(QApp)

 wxFrame * SessionThread::m_parent = 0;

 bool
  QApp::OnInit()
 {
   wxApp::OnInit();

   g_trace = true;

   wxInitAllImageHandlers();

   m_frame = new NP(NULL);

   m_frame->Centre();

   m_frame->Show();

   m_frame->n_size = m_frame->GetSize();
   
   #ifdef __WXMSW__
     WORD      wVersionRequested = 0;
     WSADATA   wsaData;

     wVersionRequested = MAKEWORD(2, 2);

     WSAStartup(wVersionRequested, &wsaData);
   #endif

   SSL_library_init();

   SSL_load_error_strings();
   
   m_mutex = new wxMutex();

   m_condition = new wxCondition(*m_mutex);

   SessionThread *t = new SessionThread(m_frame);

   wxThreadError err = t->Create();
        
   if (err != wxTHREAD_NO_ERROR) {
     return false;
   }

   err = t->Run();

   if (err != wxTHREAD_NO_ERROR) {
     return false;
   }

   return true;
 }

 void
  state_machine (connection *c)
 {
   logit_a ("%s(%d): ->\n", __func__, GetCurrentThreadId());

   assert(c);

   wxCommandEvent *e = NULL; 

   if (c->m_protocol == PROTO_FTP_CC ||
       c->m_protocol == PROTO_FTP_DC) { /* ftp */

      e = new wxCommandEvent (wxEVT_FTP, wxID_ANY);

   } else if (c->m_protocol == PROTO_XMPP) {

      e = new wxCommandEvent (wxEVT_XMPP, wxID_ANY);
   }

   e->SetClientData(c);
         
   if (wxMUTEX_NO_ERROR == m_mutex->Lock()) {

     SessionThread::m_parent->GetEventHandler()->AddPendingEvent(*e);

     delete e;

     if (wxCOND_NO_ERROR != m_condition->Wait()) {

       logit_a ("%s(%d): m_condition->Wait failed\n", __func__, GetCurrentThreadId());

     } else {

       logit_a ("%s(%d): m_condition->Wait successfull\n", __func__, GetCurrentThreadId());

       if (wxMUTEX_NO_ERROR != m_mutex->Unlock()) {

         logit_a ("%s(%d): m_mutex->Unlock failed\n", __func__, GetCurrentThreadId());
       }
     }
   } else {

     logit_a ("%s(%d): m_mutex->Lock failed\n", __func__, GetCurrentThreadId());
   }
 }

 wxThread::ExitCode
  SessionThread::Entry()
 {
   session_thread (c_list);
   return 0;
 }

 #ifndef __GNUC__

 #ifdef _DEBUG
  #pragma comment(linker, "/DEFAULTLIB:wxmsw29ud_adv.lib")
  #pragma comment(linker, "/DEFAULTLIB:wxmsw29ud_richtext.lib")
  #pragma comment(linker, "/DEFAULTLIB:wxmsw29ud_html.lib")
  #pragma comment(linker, "/DEFAULTLIB:wxbase29ud_xml.lib")
 #else
  #pragma comment(linker, "/DEFAULTLIB:wxmsw29u_adv.lib")
  #pragma comment(linker, "/DEFAULTLIB:wxmsw29u_richtext.lib")
  #pragma comment(linker, "/DEFAULTLIB:wxmsw29u_html.lib")
  #pragma comment(linker, "/DEFAULTLIB:wxbase29u_xml.lib")
 #endif

  #pragma comment(linker, "/DEFAULTLIB:libeay32.lib")
  #pragma comment(linker, "/DEFAULTLIB:ssleay32.lib")
  #pragma comment(linker, "/DEFAULTLIB:ws2_32.lib")
  #pragma comment(linker, "/DEFAULTLIB:libgsasl.lib")  

 #endif